/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.core.mgrimpl;


import com.inspur.edp.bef.component.detailcmpentity.vm.VMComponent;
import com.inspur.edp.bef.component.detailcmpentity.vm.VMMethod;
import com.inspur.edp.bef.component.detailcmpentity.vm.VMMethodParameter;
import com.inspur.edp.bff.designtime.generator.common.IMetadataPool;
import com.inspur.edp.bff.designtime.generator.core.VmCoreGenContext;
import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.cef.entity.changeset.Tuple;
import com.inspur.edp.cef.generator.overall.Utils;
import com.inspur.edp.formserver.viewmodel.action.MappedCdpAction;
import com.inspur.edp.formserver.viewmodel.action.viewmodelbase.ViewModelParActualValue;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import org.eclipse.jdt.core.dom.*;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class VmActionMethodGenerator extends ClassMethodGenerator {

  private static final String ResultVarName = "result";
  private static final String VariableName = "action";
  private static  final String Var_Parameters="parameters";
  private MappedCdpAction action;
  private IMetadataPool pool;
  private VMComponent compMetadata;
  private VMMethod method;
  private java.util.ArrayList<Tuple<String, TypeInfo>> parList;
  private VmCoreGenContext coreGenCtx;

  public VmActionMethodGenerator(MappedCdpAction action, IMetadataPool pool,
      VmCoreGenContext coreGenCtx) {
    this.action = action;
    this.pool = pool;
    this.coreGenCtx = coreGenCtx;
  }

  @Override
  protected void doInitialize() {
    GspMetadata metadata = pool
        .getMetadata(action.getComponentPkgName(), action.getComponentEntityId());
    compMetadata = (VMComponent) metadata.getContent();

    if (compMetadata == null) {
      throw new RuntimeException(
          "#GspBefError#VM动作构件【" + action.getComponentEntityId() + "】不存在#GspBefError# ");
    }
    method = compMetadata.getVmMethod();
  }

  //C# TO JAVA CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted by C# to Java Converter:
  @Override
  protected java.util.ArrayList<ModifierKeyword> getAccessModifiers() {
    return new java.util.ArrayList<ModifierKeyword>(
        java.util.Arrays.asList(new ModifierKeyword[]{ModifierKeyword.PUBLIC_KEYWORD}));
  }

  //C# TO JAVA CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted by C# to Java Converter:
  @Override
  protected String getMethodName() {
    return action.getCode();
  }

  //C# TO JAVA CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted by C# to Java Converter:
  @Override
  protected java.util.ArrayList<ParameterInfo> getParameterCollection() {
    return new ArrayList(preparePars().stream().map(item -> {
      ParameterInfo tempVar = new ParameterInfo();
      tempVar.setParamName(item.getItem1());
      tempVar.setParamType(item.getItem2());
      return tempVar;
    }).collect(Collectors.toList()));
  }

  private java.util.ArrayList<Tuple<String, TypeInfo>> preparePars() {
    if (parList == null) {
      parList = new ArrayList();
      if (method.getParams() != null) {
        for (Object obj : method.getParams()) {
          VMMethodParameter par = (VMMethodParameter)obj;
          ParameterInfo tempVar = new ParameterInfo();
          tempVar.setParamName(par.getParamCode());
          tempVar.setParamType(Utils.getNativeType(par, coreGenCtx.getVmGenContext()));
          parList.add(new Tuple(par.getParamCode(),
              Utils.getNativeType(par, coreGenCtx.getVmGenContext())));
        }
      }
    }
    return parList;
  }

  //C# TO JAVA CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted by C# to Java Converter:
  @Override
  protected TypeInfo getReturnType() {
    return Utils.getReturnType(method, coreGenCtx.getVmGenContext());
  }

  @Override
  protected Block buildMethodBody() {
    java.util.ArrayList<Statement> statements = new java.util.ArrayList<Statement>();

    statements.add(getCreateCdpStatement());
    addParametersStatements(statements);
    statements.add(getExecuteStatement());

//    if (action.getIsAutoSave()) {
//      MethodInvocation saveInvocation = ast.newMethodInvocation();
//      saveInvocation.setName(ast.newSimpleName("save"));
//      statements.add(ast.newExpressionStatement(saveInvocation));
//    }

    if (getReturnType().getTypeName() .equals( "void")==false) {
      ReturnStatement returnStatement = ast.newReturnStatement();
      returnStatement.setExpression(ast.newSimpleName(ResultVarName));
      statements.add(returnStatement);
    }

    Block block = ast.newBlock();
    block.statements().addAll(statements);
    return block;
  }

  private void addParametersStatements(ArrayList<Statement> statements) {
    addNewParameterStatement(statements);
    addParameterItemsStatements(statements);
  }

  private void addNewParameterStatement(ArrayList<Statement> statements) {
    VariableDeclarationFragment variableDeclarationFragment=ast.newVariableDeclarationFragment();
    variableDeclarationFragment.setName(ast.newSimpleName(Var_Parameters));
    variableDeclarationFragment.setInitializer(createParametersInitializerStatement());

    VariableDeclarationStatement variableDeclarationStatement=ast.newVariableDeclarationStatement(variableDeclarationFragment);
    setVarParametersType(variableDeclarationStatement);
    statements.add(variableDeclarationStatement);
  }

  private Expression createParametersInitializerStatement() {
    ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
    ParameterizedType parameterizedType=ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName(HashMap.class.getSimpleName())));
    addImport(HashMap.class.getTypeName());
    classInstanceCreation.setType(parameterizedType);
    return classInstanceCreation;
  }

  private void setVarParametersType(VariableDeclarationStatement variableDeclarationStatement) {
    ParameterizedType parameterizedType=ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName(Map.class.getSimpleName())));
    addImport(Map.class.getTypeName());
    parameterizedType.typeArguments().add(ast.newSimpleType(ast.newSimpleName(String.class.getSimpleName())));
    parameterizedType.typeArguments().add(ast.newSimpleType(ast.newSimpleName(Object.class.getSimpleName())));
    variableDeclarationStatement.setType(parameterizedType);
  }

  private void addParameterItemsStatements(ArrayList<Statement> statements) {
    java.util.ArrayList<Tuple<String, TypeInfo>> parameters =preparePars();
    if(parameters==null||parameters.size()==0)
      return;
    for(Tuple<String, TypeInfo> item:parameters)
    {
      statements.add(createAddParameterStatement(item));
    }
  }

  private Statement createAddParameterStatement(Tuple<String, TypeInfo> item) {
    MethodInvocation methodInvocation=ast.newMethodInvocation();
    methodInvocation.setExpression(ast.newSimpleName(Var_Parameters));
    methodInvocation.setName(ast.newSimpleName("put"));
    StringLiteral stringLiteral=ast.newStringLiteral();
    stringLiteral.setLiteralValue(item.getItem1());
    methodInvocation.arguments().add(stringLiteral);
    //查找对应的参数实参
    boolean enable = false;
    //todo 待优化
    for(int i=0;i<this.action.getParameterCollection().getCount();i++){
      if(this.action.getParameterCollection().getItem(i).getParamCode().equals(item.getItem1())){
        ViewModelParActualValue actualValue = this.action.getParameterCollection().getItem(i).getActualValue();
        enable = actualValue != null ? actualValue.isEnable():false;
        if(enable){
          StringLiteral stringLiteral2=ast.newStringLiteral();
          stringLiteral2.setLiteralValue(this.action.getParameterCollection().getItem(i).getActualValue().getValue());
          methodInvocation.arguments().add(stringLiteral2);
        }
        break;
      }
    }
    if(!enable){
      methodInvocation.arguments().add(ast.newSimpleName(item.getItem1()));
    }
    return ast.newExpressionStatement(methodInvocation);
  }

  private Statement getCreateCdpStatement() {
    List<String> arguments = preparePars().stream().map(item ->
        item.getItem1()).collect(Collectors.toList());
    VariableDeclarationFragment compDeclarationFragment = ast.newVariableDeclarationFragment();
    compDeclarationFragment.setName(ast.newSimpleName(VariableName));
    ClassInstanceCreation compCreation = ast.newClassInstanceCreation();
    compCreation.setType(ast.newSimpleType(ast.newName(method.getClassName())));
    for (String arg : arguments) {
      boolean enable = false;
      //todo 待优化
      for(int i=0;i<this.action.getParameterCollection().getCount();i++){
        if(this.action.getParameterCollection().getItem(i).getParamCode().equals(arg)){
          ViewModelParActualValue actualValue = this.action.getParameterCollection().getItem(i).getActualValue();
          enable = actualValue != null ? actualValue.isEnable():false;
          if(enable){
            StringLiteral stringLiteral2=ast.newStringLiteral();
            stringLiteral2.setLiteralValue(this.action.getParameterCollection().getItem(i).getActualValue().getValue());
            compCreation.arguments().add(stringLiteral2);
          }
          break;
        }
      }
      if(!enable){
        compCreation.arguments().add(ast.newSimpleName(arg));
      }
    }
    compDeclarationFragment.setInitializer(compCreation);
    VariableDeclarationStatement compDeclarationStatement = ast.newVariableDeclarationStatement(compDeclarationFragment);
    compDeclarationStatement.setType(ast.newSimpleType(ast.newName(method.getClassName())));
    return compDeclarationStatement;
  }

  private Statement getExecuteStatement() {
    MethodInvocation methodInvocation = ast.newMethodInvocation();
    methodInvocation.setName(ast.newSimpleName("executeAction"));
    methodInvocation.arguments().add(ast.newSimpleName(VariableName));
    StringLiteral stringLiteral=ast.newStringLiteral();
    stringLiteral.setLiteralValue(action.getID());
    methodInvocation.arguments().add(stringLiteral);
    StringLiteral stringLiteral1=ast.newStringLiteral();
    stringLiteral1.setLiteralValue(action.getCode());
    methodInvocation.arguments().add(stringLiteral1);
    methodInvocation.arguments().add(ast.newSimpleName(Var_Parameters));
    BooleanLiteral booleanLiteral=ast.newBooleanLiteral(action.getIsAutoSave());
    methodInvocation.arguments().add(booleanLiteral);


    if (getReturnType().getTypeName() .equals( "void")) {
      return ast.newExpressionStatement(methodInvocation);
    } else {
      VariableDeclarationFragment resultDeclarationFragment = ast.newVariableDeclarationFragment();
      resultDeclarationFragment.setName(ast.newSimpleName(ResultVarName));
      resultDeclarationFragment.setInitializer(methodInvocation);
      VariableDeclarationStatement resultDeclarationStatement = ast
          .newVariableDeclarationStatement(resultDeclarationFragment);
      resultDeclarationStatement.setType(getReturnType().getType(ast));
      return resultDeclarationStatement;
    }
  }
}
